package top.wuchu.rpc.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.wuchu.rpc.entity.RpcRequest;
import top.wuchu.rpc.entity.RpcResponse;
import top.wuchu.rpc.enumeration.PackageType;
import top.wuchu.rpc.enumeration.RpcError;
import top.wuchu.rpc.exception.RpcException;
import top.wuchu.rpc.serializer.CommonSerializer;

import java.util.List;

/**
 * 通用的解码拦截器，你收到别人发给你的数据，肯定都是经过序列化后的，并且都是编码过的。你拿到数据肯定得解码，之后封装成你想要的数据格式
 *
 * @author Wuchu
 */
public class CommonDecoder extends ReplayingDecoder {

    private static final Logger logger = LoggerFactory.getLogger(CommonDecoder.class);

    private static final int MAGIC_NUMBER = 0xCAFEBABE; // 这只是一个标识，只有带有这个标识的数据包才能使用

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {

        // 自定义的网络传输包的数据格式
//            +---------------+---------------+-----------------+-------------+
//            |  Magic Number |  Package Type | Serializer Type | Data Length |
//            |    4 bytes    |    4 bytes    |     4 bytes     |   4 bytes   |
//            +---------------+---------------+-----------------+-------------+
//            |                          Data Bytes                           |
//            |                   Length: ${Data Length}                      |
//            +---------------------------------------------------------------+

        // 数据包标识
        int magic = in.readInt();
        if (magic != MAGIC_NUMBER) {
            logger.error("不识别的协议包: {}", magic);
            throw new RpcException(RpcError.UNKNOWN_PROTOCOL);
        }

        // 数据包的类型：请求包还是响应包
        int packageCode = in.readInt();
        Class<?> packageClass;
        if (packageCode == PackageType.REQUEST_PACK.getCode()) {
            packageClass = RpcRequest.class;
        } else if (packageCode == PackageType.RESPONSE_PACK.getCode()) {
            packageClass = RpcResponse.class;
        } else {
            logger.error("不识别的数据包: {}", packageCode);
            throw new RpcException(RpcError.UNKNOWN_PACKAGE_TYPE);
        }

        // 序列化协议
        int serializerCode = in.readInt();
        CommonSerializer serializer = CommonSerializer.getByCode(serializerCode);
        if (serializer == null) {
            logger.error("不识别的反序列化器: {}", serializerCode);
            throw new RpcException(RpcError.UNKNOWN_SERIALIZER);
        }

        // 数据包的长度，防止出现粘包问题
        int length = in.readInt();

        // 接收的数据
        byte[] bytes = new byte[length];
        in.readBytes(bytes);

        // 通过反序列化将接收的数据转变为对象
        Object obj = serializer.deserialize(bytes, packageClass);
        out.add(obj);
    }

}
